home *** CD-ROM | disk | FTP | other *** search
/ World of Education / World of Education.iso / world_p / pcshx10b.zip / PCSHX10B.EXE / GNUFGREP.EXE / GREPDOCS.EXE / FGREP.C < prev    next >
C/C++ Source or Header  |  1990-09-06  |  17KB  |  800 lines

  1. /* fgrep.c - grep program built around matcher.
  2.    Copyright 1989 Free Software Foundation
  3.           Written August 1989 by Mike Haertel.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 1, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.    The author may be reached (Email) at the address mike@ai.mit.edu,
  20.    or (US mail) as Mike Haertel c/o Free Software Foundation. */
  21.  
  22. /*-
  23.    MODIFIED FOR MSDOS BY BARRY SCHWARTZ, AUGUST 1990.
  24.  
  25.    Includes new option:
  26.     `-d <expression>'   Same as -e, except strips bracketing quotes
  27.  */
  28.  
  29. #ifdef MSDOS
  30. #include "msdosmac.h"
  31. #include <fcntl.h>
  32. #endif
  33.  
  34. #include "std.h"
  35. #include "unix.h"
  36.  
  37. #include <errno.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40.  
  41. #include "kwset.h"
  42.  
  43. #define NCHAR (UCHAR_MAX + 1)
  44.  
  45. /* For error messages. */
  46. static const char *prog;
  47. static int error_seen;
  48.  
  49. /* Flags controlling the style of output. */
  50. static int out_silent;        /* Suppress all normal output. */
  51. static int out_invert;        /* Print nonmatching stuff. */
  52. static int out_file;        /* Print filenames. */
  53. static int out_line;        /* Print line numbers. */
  54. static int out_byte;        /* Print byte offsets. */
  55. static int out_before;        /* Lines of leading context. */
  56. static int out_after;        /* Lines of trailing context. */
  57.  
  58. /* Print MESG and possibly the error string for ERRNUM.  Remember
  59.    that something awful happened. */
  60. static void
  61. DEFUN(error, (mesg, errnum), const char *mesg AND int errnum)
  62. {
  63.   if (errnum)
  64.     fprintf(stderr, "%s: %s: %s\n", prog, mesg, strerror(errnum));
  65.   else
  66.     fprintf(stderr, "%s: %s\n", prog, mesg);
  67.   error_seen = 1;
  68. }
  69.  
  70. /* Like error(), but die horribly after printing. */
  71. static void
  72. DEFUN(fatal, (mesg, errnum), const char *mesg AND int errnum)
  73. {
  74.   error(mesg, errnum);
  75.   exit(2);
  76. }
  77.  
  78. /* Interface to handle errors and fix library lossage. */
  79. static PTR
  80. DEFUN(xmalloc, (size), size_t size)
  81. {
  82.   PTR result;
  83.  
  84.   result = malloc(size);
  85.   if (size && !result)
  86.     fatal("memory exhausted", 0);
  87.   return result;
  88. }
  89.  
  90. /* Interface to handle errors and fix some library lossage. */
  91. static PTR
  92. DEFUN(xrealloc, (ptr, size), PTR ptr AND size_t size)
  93. {
  94.   PTR result;
  95.  
  96.   if (ptr)
  97.     result = realloc(ptr, size);
  98.   else
  99.     result = malloc(size);
  100.   if (size && !result)
  101.     fatal("memory exhausted", 0);
  102.   return result;
  103. }
  104.  
  105. /* Compiled search pattern. */
  106. kwset_t kwset;
  107.  
  108. /* Flags controlling how pattern matching is performed. */
  109. static int match_fold;        /* Fold all letters to one case. */
  110. static int match_words;        /* Match only whole words. */
  111. static int match_lines;        /* Match only whole lines. */
  112.  
  113. static void
  114. DEFUN(compile, (pattern, size), const char *pattern AND size_t size)
  115. {
  116.   const char *beg, *lim, *err;
  117.   static char trans[NCHAR];
  118.   int i;
  119.  
  120.   if (match_fold)
  121.     for (i = 0; i < NCHAR; ++i)
  122.       trans[i] = TOLOWER(i);
  123.  
  124.   if (!(kwset = kwsalloc(match_fold ? trans : (const char *) NULL)))
  125.     fatal("memory exhausted", 0);
  126.  
  127.   beg = pattern;
  128.   do
  129.     {
  130.       for (lim = beg; lim < pattern + size && *lim != '\n'; ++lim)
  131.     ;
  132.       if (err = kwsincr(kwset, beg, lim - beg))
  133.     fatal(err, 0);
  134.       if (lim < pattern + size)
  135.     ++lim;
  136.       beg = lim;
  137.     }
  138.   while (beg < pattern + size);
  139.  
  140.   if (err = kwsprep(kwset))
  141.     fatal(err, 0);
  142. }
  143.  
  144. static char *
  145. DEFUN(execute, (buf, size), char *buf AND size_t size)
  146. {
  147.   register char *beg, *try;
  148.   register size_t len;
  149.   struct kwsmatch kwsmatch;
  150.  
  151.   beg = buf;
  152.   for (;beg <= buf + size; ++beg)
  153.     {
  154.       if (!(beg = kwsexec(kwset, beg, buf + size - beg, &kwsmatch)))
  155.     return NULL;;
  156.       len = kwsmatch.size[0];
  157.       if (match_lines)
  158.     {
  159.       /* Check that the match starts at the beginning of a line */
  160.       if (beg > buf && beg[-1] != '\n')
  161.         continue;
  162.  
  163. #ifndef MSDOS
  164.       /* Check that the match ends at the end of a line */
  165.       if (beg + len < buf + size && *(beg + len) != '\n')
  166.         continue;
  167. #else
  168.       /* Check that the match ends at the end of a line */
  169.       /* A line can end with either '\n' or '\r\n' */
  170.       {
  171.         register char *p = beg + len;
  172.         register char *q = buf + size;
  173.  
  174.         if (p < q)
  175.           switch (*p)
  176.             {
  177.             case '\n':
  178.           break;
  179.             case '\r':
  180.           if (p + 1 < q && *(p + 1) != '\n')
  181.             continue;
  182.           break;
  183.             default:
  184.           continue;
  185.             }
  186.       }
  187. #endif
  188.  
  189.       return beg;
  190.     }
  191.       else if (match_words)
  192.     for (try = beg; len && try;)
  193.       {
  194.         if (try > buf && (ISALNUM((unsigned char) try[-1])
  195.                   || !ISALNUM((unsigned char) *try)))
  196.           goto retry;
  197.         if (try + len < buf + size
  198.         && (ISALNUM((unsigned char) *(try + len))
  199.             || !ISALNUM((unsigned char) (try + len)[-1])))
  200.           goto retry;
  201.         return try;
  202.       retry:
  203.         if (--len)
  204.           try = kwsexec(kwset, beg, len, &kwsmatch);
  205.         else
  206.           break;
  207.         len = kwsmatch.size[0];
  208.       }
  209.       else
  210.     return beg;
  211.     }
  212.  
  213.   return NULL;
  214. }
  215.  
  216. /* Hairy buffering mechanism to efficiently support all the options. */
  217. static char *bufbeg;        /* Beginning of user-visible portion. */
  218. static char *buflim;        /* Limit of user-visible portion. */
  219. static char *buf;        /* Pointer to base of buffer. */
  220. static size_t bufalloc;        /* Allocated size of buffer. */
  221. static size_t bufcc;        /* Count of characters in buffer. */
  222. static unsigned long int buftotalcc;
  223.                 /* Total character count since reset. */
  224. static char *buflast;        /* Pointer after last character printed. */
  225. static int bufgap;        /* Weird flag indicating buflast is a lie. */
  226. static unsigned long int buftotalnl;
  227.                 /* Count of newlines before last character. */
  228. static int bufpending;        /* Lines of pending output at buflast. */
  229. static int bufdesc;        /* File descriptor to read from. */
  230. static int bufeof;        /* Flag indicating EOF reached. */
  231. static const char *buffile;    /* File name for messages. */
  232.  
  233. /* Scan and count the newlines prior to LIM in the buffer. */
  234. static void
  235. DEFUN(nlscan, (lim), register char *lim)
  236. {
  237.   register char *p;
  238.  
  239.   for (p = buflast; p < lim; ++p)
  240.     if (*p == '\n')
  241.       ++buftotalnl;
  242.   buflast = lim;
  243. }
  244.  
  245. /* Print the line beginning at BEG, using SEP to separate optional label
  246.    fields from the text of the line.  Return the size of the line. */
  247. static size_t
  248. DEFUN(prline, (beg, sep), register char *beg AND register char sep)
  249. {
  250.   register size_t cc;
  251.   register char c;
  252.   static int err;
  253.   
  254.   cc = 0;
  255.  
  256.   if (out_silent || err)
  257.     while (beg < buflim)
  258.       {
  259.     ++cc;
  260.     if (*beg++ == '\n')
  261.       break;
  262.       }
  263.   else
  264.     {
  265.       if (out_file)
  266.     printf("%s%c", buffile, sep);
  267.       if (out_line)
  268.     {
  269.       nlscan(beg);
  270.       printf("%lu%c", buftotalnl + 1, sep);
  271.     }
  272. #ifndef MSDOS
  273.       if (out_byte)
  274.     printf("%lu%c", buftotalcc + (beg - buf), sep);
  275. #else
  276.       if (out_byte)
  277.     printf("%lu%c",
  278.                buftotalcc + ((char far *) beg - (char far *) buf), sep);
  279. #endif
  280.       while (beg < buflim)
  281.     {
  282.       ++cc;
  283.       c = *beg++;
  284. #ifndef MSDOS
  285.       putchar(c);
  286. #else
  287.       /* Convert any CR-LF sequences to \n */
  288.       if (c != '\r' || (beg < buflim && *beg != '\n'))
  289.         putchar(c);
  290. #endif
  291.       if (c == '\n')
  292.         break;
  293.     }
  294.       if (ferror(stdout))
  295.     {
  296.       error("output error", errno);
  297.       err = 1;
  298.     }
  299.     }
  300.  
  301.   if (out_line)
  302.     nlscan(beg);
  303.   else
  304.     buflast = beg;
  305.   bufgap = 0;
  306.  
  307.   return cc;
  308. }
  309.  
  310. /* Print pending bytes of last trailing context prior to LIM. */
  311. static void
  312. DEFUN(prpending, (lim), register char *lim)
  313. {
  314.   while (buflast < lim && bufpending)
  315.     {
  316.       --bufpending;
  317.       prline(buflast, '-');
  318.     }
  319. }
  320.  
  321. /* Print the lines between BEG and LIM.  Deal with context crap.
  322.    Return the count of lines between BEG and LIM. */
  323. #ifndef MSDOS
  324. static int
  325. #else
  326. static unsigned long
  327. #endif
  328. DEFUN(prtext, (beg, lim), char *beg AND char *lim)
  329. {
  330.   static int used;
  331.   register char *p;
  332. #ifndef MSDOS
  333.   int i, n;
  334. #else
  335.   int i;
  336.   unsigned long n;
  337. #endif
  338.  
  339.   prpending(beg);
  340.  
  341.   p = beg;
  342.   for (i = 0; i < out_before; ++i)
  343.     if (p > buflast)
  344.       do
  345.     --p;
  346.       while (p > buflast && p[-1] != '\n');
  347.  
  348.   if ((out_before || out_after) && used && (p > buflast || bufgap))
  349.     puts("--");
  350.  
  351.   while (p < beg)
  352.     p += prline(p, '-');
  353.  
  354.   n = 0;
  355.   while (p < lim)
  356.     {
  357.       ++n;
  358.       p += prline(p, ':');
  359.     }
  360.  
  361.   bufpending = out_after;
  362.   used = 1;
  363.  
  364.   return n;
  365. }
  366.  
  367. /* Fill the user-visible portion of the buffer, returning a byte count. */
  368. static int
  369. fillbuf()
  370. {
  371.   register char *b, *d, *l;
  372.   int i, cc;
  373.   size_t discard, save;
  374.  
  375.   prpending(buflim);
  376.  
  377.   b = buflim;
  378.   for (i = 0; i < out_before; ++i)
  379.     if (b > buflast)
  380.       do
  381.     --b;
  382.       while (b > buflast && b[-1] != '\n');
  383.  
  384.   if (buflast < b)
  385.     bufgap = 1;
  386.   if (out_line)
  387.     nlscan(b);
  388.  
  389.   discard = b - buf;
  390.   save = buflim - b;
  391.  
  392.   if (b > buf)
  393.     {
  394.       d = buf;
  395.       l = buf + bufcc;
  396.       while (b < l)
  397.     *d++ = *b++;
  398.     }
  399.  
  400.   bufcc -= discard;
  401.   buftotalcc += discard;
  402.  
  403.   do
  404.     {
  405.       if (!bufeof)
  406.     {
  407.       if (bufcc > bufalloc / 2)
  408.         buf = xrealloc(buf, bufalloc *= 2);
  409.       cc = read(bufdesc, buf + bufcc, bufalloc - bufcc);
  410.       if (cc < 0)
  411.         {
  412.           error(buffile, errno);
  413.           bufeof = 1;
  414.         }
  415.       else
  416.         {
  417.           bufeof = !cc;
  418.           bufcc += cc;
  419.         }
  420.     }
  421.       bufbeg = buf + save;
  422.       for (l = buf + bufcc; l > bufbeg && l[-1] != '\n'; --l)
  423.     ;
  424.       buflim = l;
  425.       buflast = buf;
  426.     }
  427.   while (!bufeof && bufbeg == buflim);
  428.  
  429.   if (bufeof)
  430.     buflim = buf + bufcc;
  431.  
  432.   return buflim - bufbeg;
  433. }
  434.  
  435. /* One-time initialization. */
  436. static void
  437. initbuf()
  438. {
  439.   bufalloc = 8192;
  440.   buf = xmalloc(bufalloc);
  441. }
  442.  
  443. /* Reset the buffer for a new file. */
  444. static void
  445. DEFUN(resetbuf, (desc, file), int desc AND const char *file)
  446. {
  447.   bufbeg = buf;
  448.   buflim = buf;
  449.   bufcc = 0;
  450.   buftotalcc = 0;
  451.   buflast = buf;
  452.   bufgap = 0;
  453.   buftotalnl = 0;
  454.   bufpending = 0;
  455.   bufdesc = desc;
  456.   bufeof = 0;
  457.   buffile = file;
  458. }
  459.  
  460. /* Scan the user-visible portion of the buffer, calling prtext() for
  461.    matching lines (or between matching lines if OUT_INVERT is true).
  462.    Return a count of lines printed. */
  463. #ifndef MSDOS
  464. static int
  465. #else
  466. static unsigned long
  467. #endif
  468. grepbuf()
  469. {
  470. #ifndef MSDOS
  471.   int total;
  472. #else
  473.   unsigned long total;
  474. #endif
  475.   register char *p, *b, *l;
  476.  
  477.   total = 0;
  478.   p = bufbeg;
  479.   while (b = execute(p, buflim - p))
  480.     {
  481.       if (b == buflim && (b > bufbeg && b[-1] == '\n' || b == bufbeg))
  482.     break;
  483.       while (b > bufbeg && b[-1] != '\n')
  484.     --b;
  485.       l = b + 1;
  486.       while (l < buflim && l[-1] != '\n')
  487.     ++l;
  488.       if (!out_invert)
  489.     total += prtext(b, l);
  490.       else if (p < b)
  491.     total += prtext(p, b);
  492.       p = l;
  493.     }
  494.   if (out_invert && p < buflim)
  495.     total += prtext(p, buflim);
  496.   return total;
  497. }
  498.  
  499. /* Scan the given file, returning a count of lines printed. */
  500. #ifndef MSDOS
  501. static int
  502. #else
  503. static unsigned long
  504. #endif
  505. DEFUN(grep, (desc, file), int desc AND const char *file)
  506. {
  507. #ifndef MSDOS
  508.   int total;
  509. #else
  510.   unsigned long total;
  511. #endif
  512.  
  513.   total = 0;
  514.   resetbuf(desc, file);
  515.   while (fillbuf())
  516.     total += grepbuf();
  517.   return total;
  518. }
  519.  
  520. static const char version[] = "GNU fgrep, version 1.1";
  521.  
  522. #ifdef MSDOS
  523. #define USAGE \
  524. "\
  525. usage: %s [-[[AB] ]<num>] [-[CVchilnsvwx]] [-[def]] <expr> [<files...>]\n\
  526.        (`-d <expr>' strips bracketing quotes off of <expr>)\n"
  527. #else
  528. #define USAGE \
  529.   "usage: %s [-[[AB] ]<num>] [-[CVchilnsvwx]] [-[ef]] <expr> [<files...>]\n"
  530. #endif
  531.  
  532. static void
  533. usage()
  534. {
  535.   fprintf(stderr, USAGE, prog);
  536.   exit(2);
  537. }
  538.  
  539. #ifdef MSDOS
  540. #ifdef GNU_GLOBBING
  541.  
  542. /* File attributes used by msd_dir2 routines */
  543. unsigned short dos_file_attributes;
  544.  
  545. #endif
  546. #endif
  547.  
  548. int
  549. DEFUN(main, (argc, argv), int argc AND char *argv[])
  550. {
  551.   char *keys;
  552.   size_t keycc, keyalloc;
  553.   int count_matches, no_filenames, list_files;
  554. #ifndef MSDOS
  555.   int opt, cc, desc, count, status;
  556. #else
  557.   int opt, cc, desc, status;
  558.   unsigned long count;
  559. #endif
  560.   FILE *fp;
  561.  
  562. #ifdef MSDOS
  563.   setmode (fileno (stdin), O_BINARY);
  564.   setmode (fileno (stdout), O_TEXT);
  565.  
  566. #ifdef GNU_GLOBBING
  567.   dos_file_attributes = 0x11;    /* Regular, read-only, or directory */
  568.   {
  569.     char **glob_filename ();
  570.     int globargv ();
  571.  
  572.     if (globargv (&argc, &argv, glob_filename) < 0)
  573.       fatal("memory exhausted", 0);
  574.   }
  575. #endif
  576.  
  577.   EXTRACT_PROGRAM_NAME(argv[0]);
  578. #endif
  579.  
  580.   prog = argv[0];
  581.  
  582. #ifndef MSDOS
  583.   if (prog && strrchr(prog, '/'))
  584.     prog = strrchr(prog, '/') + 1;
  585. #endif
  586.  
  587.   keys = NULL;
  588.   count_matches = 0;
  589.   no_filenames = 0;
  590.   list_files = 0;
  591.  
  592. #ifndef MSDOS
  593.   while ((opt = getopt(argc, argv, "0123456789A:B:CVbce:f:hilnsvwxy")) != EOF)
  594. #else
  595.   /* Includes the `-d' option for MSDOS */
  596.   while ((opt = getopt(argc, argv, "0123456789A:B:CVbcd:e:f:hilnsvwxy"))
  597.        != EOF)
  598. #endif
  599.     switch (opt)
  600.       {
  601.       case '0':
  602.       case '1':
  603.       case '2':
  604.       case '3':
  605.       case '4':
  606.       case '5':
  607.       case '6':
  608.       case '7':
  609.       case '8':
  610.       case '9':
  611.     out_before = 10 * out_before + opt - '0';
  612.     out_after = 10 * out_after + opt - '0';
  613.     break;
  614.       case 'A':
  615.     out_after = atoi(optarg);
  616.     if (out_after < 0)
  617.       usage();
  618.     break;
  619.       case 'B':
  620.     out_before = atoi(optarg);
  621.     if (out_before < 0)
  622.       usage();
  623.     break;
  624.       case 'C':
  625.     out_before = out_after = 2;
  626.     break;
  627.       case 'V':
  628.     fprintf(stderr, "%s\n", version);
  629.     break;
  630.       case 'b':
  631.     out_byte = 1;
  632.     break;
  633.       case 'c':
  634.     out_silent = 1;
  635.     count_matches = 1;
  636.     break;
  637.       case 'e':
  638.     if (keys)
  639.       usage();
  640.     keys = optarg;
  641.     keycc = strlen(keys);
  642.     break;
  643. #ifdef MSDOS
  644.       case 'd':
  645.     if (keys)
  646.       usage();
  647.     /* Strip off bracketing quotes */
  648.     if (optarg[0] == '\'' || optarg[0] == '"')
  649.       {
  650.         char opening_quote = optarg[0];
  651.         int len = strlen (optarg);
  652.  
  653.         if (len > 1 && optarg[len - 1] == opening_quote)
  654.           (optarg++)[len - 1] = '\0';
  655.       }
  656.     keys = optarg;
  657.     keycc = strlen(keys);
  658.     break;
  659. #endif
  660.       case 'f':
  661.     if (keys)
  662.       usage();
  663. #ifdef MSDOS
  664.     CONVERT_TO_SLASHES(optarg);
  665. #endif
  666. #ifndef MSDOS
  667.     fp = strcmp(optarg, "-") ? fopen(optarg, "r") : stdin;
  668. #else
  669.     /* For some reason Microsoft C gives a warning about the above
  670.      * construct, so here's an alternative construct. */
  671.     if (strcmp(optarg, "-"))
  672.       fp = fopen(optarg, "r");
  673.     else
  674.       fp = stdin;
  675. #endif
  676.     if (!fp)
  677.       fatal(optarg, errno);
  678. #ifdef MSDOS
  679.     /* This file has to be in text mode */
  680.     setmode(fileno(fp), O_TEXT);
  681. #endif
  682.     keyalloc = 1024;
  683.     keys = xmalloc(keyalloc);
  684.     keycc = 0;
  685.     while (!feof(fp)
  686.            && (cc = fread(keys + keycc, 1, keyalloc - keycc, fp)) > 0)
  687.       {
  688.         keycc += cc;
  689.         if (keycc == keyalloc)
  690.           keys = xrealloc(keys, keyalloc *= 2);
  691.       }
  692.     if (fp != stdin)
  693.       fclose(fp);
  694. #ifdef MSDOS
  695.     else
  696.       setmode(fileno(stdin), O_BINARY);
  697. #endif
  698.     break;
  699.       case 'h':
  700.     no_filenames = 1;
  701.     break;
  702.       case 'i':
  703.       case 'y':            /* For old-timers . . . */
  704.     match_fold = 1;
  705.     break;
  706.       case 'l':
  707.     out_silent = 1;
  708.     list_files = 1;
  709.     break;
  710.       case 'n':
  711.     out_line = 1;
  712.     break;
  713.       case 's':
  714.     out_silent = 1;
  715.     break;
  716.       case 'v':
  717.     out_invert = 1;
  718.     break;
  719.       case 'w':
  720.     match_words = 1;
  721.     break;
  722.       case 'x':
  723.     match_lines = 1;
  724.     break;
  725.       default:
  726.     usage();
  727.     break;
  728.       }
  729.  
  730.   if (!keys)
  731.     if (optind < argc)
  732.       {
  733.     keys = argv[optind++];
  734.     keycc = strlen(keys);
  735.       }
  736.     else
  737.       usage();
  738.  
  739.   compile(keys, keycc);
  740.  
  741.   if (argc - optind > 1 && !no_filenames)
  742.     out_file = 1;
  743.  
  744.   status = 1;
  745.   initbuf();
  746.  
  747.   if (optind < argc)
  748.     while (optind < argc)
  749.       {
  750. #ifdef MSDOS
  751.     CONVERT_TO_SLASHES(argv[optind]);
  752. #endif
  753.     desc = strcmp(argv[optind], "-") ? open(argv[optind], 0) : 0;
  754.     if (desc < 0)
  755.       error(argv[optind], errno);
  756.     else
  757.       {
  758.         count = grep(desc, argv[optind]);
  759.         if (count_matches)
  760.           {
  761.         if (out_file)
  762.           printf("%s:", argv[optind]);
  763. #ifndef MSDOS
  764.         printf("%d\n", count);
  765. #else
  766.         printf("%lu\n", count);
  767. #endif
  768.           }
  769.         if (count)
  770.           {
  771.         status = 0;
  772.         if (list_files)
  773.           printf("%s\n", argv[optind]);
  774.           }
  775.       }
  776.     if (desc)
  777.       close(desc);
  778.     ++optind;
  779.       }
  780.   else
  781.     {
  782.       count = grep(0, "<stdin>");
  783. #ifndef MSDOS
  784.       if (count_matches)
  785.     printf("%d\n", count);
  786. #else
  787.       if (count_matches)
  788.     printf("%lu\n", count);
  789. #endif
  790.       if (count)
  791.     {
  792.       status = 0;
  793.       if (list_files)
  794.         printf("%s\n", argv[optind]);
  795.     }
  796.     }
  797.  
  798.   exit(error_seen ? 2 : status);
  799. }
  800.